/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package actioncombination.problem.gridworld;

import actioncombination.logic.environment.*;
import actioncombination.problem.gridworld.GridWorldState;
import actioncombination.common.value.DoubleValue;
import actioncombination.logic.agent.AgentState;
import actioncombination.problem.gridworld.GoalTestImpl;
import actioncombination.common.value.IntegerValue;
import actioncombination.common.value.Point2DIntegerValue;


import actioncombination.logic.agent.Agent;
import actioncombination.logic.agent.RLAgent;
import actioncombination.problem.gridworld.PerceptionImpl;

import actioncombination.problem.gridworld.AgentStateImpl;
import actioncombination.logic.agent.action.Action;



import actioncombination.logic.agent.action.ActionDirection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

/**
 *
 * @author gisia
 */
public class GridWorld extends RLEnvironment {

    //definir las recompensas 
    
    
    public GridWorld(RLAgent agent, int binsX, int binsY) {
              super(new GridWorldState(new int[binsY][binsX]));
              ((GridWorldState)this.getEnvironmentState()).setBinsX(binsX);
              ((GridWorldState)this.getEnvironmentState()).setBinsX(binsY);
              this.setAgentRL(agent);
              this.createEnvironment();
    }

    @Override
    public DoubleValue getReward(Agent agent) {
        PerceptionImpl p = (PerceptionImpl) this.getPercept(agent);
        this.setAgentRL((RLAgent) agent);       
        Point2DIntegerValue pair = ((AgentStateImpl) this.getAgentRL().getAgentState()).getPosition();
        
        if (p.getSensor() == PerceptionImpl.PERCEPTION_OUT) {
            //borro la lista de targets visitados
            ((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().clear();
            return new DoubleValue(-1);
            
        } else if(p.getSensor() == PerceptionImpl.PERCEPTION_TARGET){
            //pregunto si es un target ya visitado o uno nuevo
            if(((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().contains(pair)){
                return new DoubleValue(1);
            }else {
                ((GridWorldState) this.getEnvironmentState()).addVisitedTarget(pair);
                return new DoubleValue(10);
            }
            
        } else if (p.getSensor() == PerceptionImpl.PERCEPTION_END) {
            //pregunto si visito todos los targets
            if (((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().size() == ((GridWorldState) this.getEnvironmentState()).getCoordTargets().size()) {
                ((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().clear();
                return new DoubleValue(10);
            } else {
                ((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().clear();
                return new DoubleValue(5);
            }
            
        } else if (p.getSensor() == PerceptionImpl.PERCEPTION_HOLE) {
            //borro la lista de targets visitados
            ((GridWorldState) this.getEnvironmentState()).getCoordVisitedTargets().clear();
            return new DoubleValue(-1);
            
        } else {
            return new DoubleValue(0);
        }

    }

    @Override
    protected void createEnvironment() {
        GoalTestImpl meta=new GoalTestImpl();
        
        //se generan las instancias de los operadores del Agente
        Vector<Action> acciones = new Vector<Action>();
        acciones.add(new GoUp());
        acciones.add(new TurnLeft());
        acciones.add(new TurnRight());
        acciones.add(new GoDown());    
       
        this.getAgentRL().setActions(acciones);
      
        
    }
    
     @Override
    public Collection<AgentState> getNextPosiblesActionsStates(RLAgent agent) {
        throw new UnsupportedOperationException("Not supported yet.");
//        int actualBin=agent.getState().getBin();
//
//        ArrayList<AgentState> nextStates=new ArrayList<AgentState>();
//        nextStates.add(agent.getKnowledge().findById(actualBin + 1,true));
//        nextStates.add(agent.getKnowledge().findById(actualBin - 1,true));

    }

   
    private class TurnRight extends ActionDirection {

    @Override
    public AgentState execute(AgentState state) {
         AgentStateImpl est = (AgentStateImpl) state;
        Point2DIntegerValue pos=est.getPosition();
       
        //Si no esta en la ultima fila se mueve para abajo
        //sino no se mueve
        if(pos.getX()+1<((GridWorldState)getEnvironmentState()).getBinsX())
            pos.setY(pos.getX()+1);              
       
        est.setPosition(pos);
        
        return est;
    }

    @Override
    public EnvironmentState execute(AgentState ast, EnvironmentState est) {
        RLEnvironmentState estado=(RLEnvironmentState) est;
        return estado;
    }

    @Override
    public Double getCost() {
        return 1.0;
    }

    @Override
    public String toString() {
        return "TurnRight";
    }

}
    
    private class TurnLeft extends ActionDirection {

    @Override
    public AgentState execute(AgentState state) {
        AgentStateImpl est = (AgentStateImpl) state;
        Point2DIntegerValue pos=est.getPosition();
       
        //Si no esta en la primer columna se mueve para la izquierda
        //sino no se mueve
        if(pos.getX()-1>0)
            pos.setY(pos.getX()-1);              
       
        est.setPosition(pos);
        
        return est;
    }

    @Override
    public EnvironmentState execute(AgentState ast, EnvironmentState est) {
        RLEnvironmentState estado=(RLEnvironmentState) est;
        return estado;
    }

    @Override
    public Double getCost() {
        return 1.0;
    }

    @Override
    public String toString() {
        return "TurnLeft";
    }
}
    
    private class GoUp extends ActionDirection {

    @Override
    public AgentState execute(AgentState state) {
         AgentStateImpl est = (AgentStateImpl) state;
        Point2DIntegerValue pos=est.getPosition();
       
        //Si no esta en la primera fila se mueve para arriba
        //sino no se mueve
        if(pos.getY()>0)
            pos.setY(pos.getY()-1);              
       
        est.setPosition(pos);
        
        return est;
    }

    @Override
    public EnvironmentState execute(AgentState ast, EnvironmentState est) {
        RLEnvironmentState estado=(RLEnvironmentState) est;
        return estado;
    }

    @Override
    public Double getCost() {
        return 1.0;
    }

    @Override
    public String toString() {
        return "GoUp";
    }
}
    
    private class GoDown extends ActionDirection {

    @Override
    public AgentState execute(AgentState state) {
        AgentStateImpl est = (AgentStateImpl) state;
        Point2DIntegerValue pos=est.getPosition();
       
        //Si no esta en la ultima fila se mueve para abajo
        //sino no se mueve
        if(pos.getY()+1<((GridWorldState)getEnvironmentState()).getBinsY())
            pos.setY(pos.getY()+1);              
       
        est.setPosition(pos);
        
        return est;
    }

    @Override
    public EnvironmentState execute(AgentState ast, EnvironmentState est) {
        RLEnvironmentState estado=(RLEnvironmentState) est;
        return estado;
    }

    @Override
    public Double getCost() {
        return 1.0;
    }

    @Override
    public String toString() {
        return "GoDown";
    }
}
  
    
    
    
}
